﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using FitNesseRunner;
using FitNesseRunner.Model;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace FitNesseRunnerTests
{
	[TestClass]
	public class VariablesHandlerShould
	{
		private class AssemblyLoaderDouble : IAssemblyLoader
		{
			private readonly List<string> _loadedAssemblies = new List<string>();
			public AssemblyLoaderDouble()
			{
				_loadedAssemblies = new List<string>();
			}

			public ICollection LoadedAssemblies
			{
				get { return _loadedAssemblies; }
			}

			public void LoadAssembliesFrom(string classPath)
			{
				_loadedAssemblies.Add(classPath);
			}
		}

		private readonly AssemblyLoaderDouble _assemblyLoader = new AssemblyLoaderDouble();

		[TestMethod]
		public void ReturnAllNormalLines()
		{
			var lines = new[]
			            	{
			            		"line1",
			            		"line2"
			            	};

			AssertCorrectLinesReturned(lines, lines);
		}

		[TestMethod]
		public void NotReturnVariableDefinitionLine()
		{
			const string line = "!define x {1}";
			AssertCorrectLinesReturned(Enumerable.Empty<string>(), new[] {line});
		}

		[TestMethod]
		public void ReplaceVariableReferenceWithItsValue()
		{
			var lines = new[]
			            	{
			            		"!define x {1}",
			            		"The value of x is ${x}"
			            	};

			var expectedLines = new[]
			                    	{
										"The value of x is 1"
			                    	};
			AssertCorrectLinesReturned(expectedLines, lines);

		}

		[TestMethod]
		public void ReplaceVariableReferenceWithItsValueUsingParenthesis()
		{
			var lines = new[]
			            	{
			            		"!define x (1)",
			            		"The value of x is ${x}"
			            	};

			var expectedLines = new[]
			                    	{
										"The value of x is 1"
			                    	};
			AssertCorrectLinesReturned(expectedLines, lines);

		}

		[TestMethod]
		public void ReplaceVariablesInPathDeclarations()
		{
			var lines = new[]
			            	{
			            		"!define x {something}",
			            		"!path prefix${x}suffix"
			            	};
			var expected = Enumerable.Empty<string>();
			AssertCorrectLinesReturned(expected, lines);
			CollectionAssert.Contains(_assemblyLoader.LoadedAssemblies, "prefix" + "something" + "suffix");
		}

		[TestMethod]
		public void HandleVariablesWithSpaces()
		{
			var lines = new[]
			            	{
			            		"!define x (a b)",
			            		"The value of x is '${x}'"
			            	};

			var expectedLines = new[]
			                    	{
										"The value of x is 'a b'"
			                    	};
			AssertCorrectLinesReturned(expectedLines, lines);
		}

		[TestMethod]
		public void ReplaceTransitiveVariables()
		{
			var lines = new[]
			            	{
			            		"!define x {1}",
								"!define y (${x}2)",
			            		"The value of y is '${y}'"
			            	};

			var expectedLines = new[]
			                    	{
										"The value of y is '12'"
			                    	};
			AssertCorrectLinesReturned(expectedLines, lines);
		}

		private void AssertCorrectLinesReturned(IEnumerable<string> expectedLines, IEnumerable<string> lines)
		{
			var handler = new VariablesHandler(lines, _assemblyLoader);
			CollectionAssert.AreEqual(new List<string>(expectedLines), new List<string>(handler.GetAllLines()));
		}
	}
}
